/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: ap3216cApp.c
作者		: 正点原子Linux团队
版本		: V1.0
描述		: ap3216c设备测试APP。
其他		: 无
使用方法	 ：./ap3216cApp /dev/ap3216c
论坛		: www.openedv.com
日志		: 初版V1.0 2021/03/19 正点原子Linux团队创建
***************************************************************/
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <signal.h>


static int noblock_fd = -1;
static int block_fd = -1;

void sig_handler(int signum, siginfo_t *siginfo, void *p)
{
	int ret;
	int64_t width;

	if(signum == SIGIO)
	{
		if(siginfo->si_band & POLLIN)
		{
			//设备有数据可读
			ret = read(noblock_fd, &width, sizeof(width));
			if(ret == sizeof(width))
				printf("width: %lld\r\n", width);
			else
				printf("read failed\r\n");
		}
	}
}

void noblock_test(char *file)
{
	int flag;
	struct sigaction act;

	printf("noblock mode\r\n");

	/* 1、注册信号处理函数 */
	if(sigaction(SIGIO, NULL, &act) < 0)	//获取之前的信号处理方式
	{
		perror("error");
		return ;
	}
	sigemptyset(&act.sa_mask);				//清空信号集
	sigaddset(&act.sa_mask, SIGIO);			//添加SIGIO到信号集，处理过程中要屏蔽SIGIO
	act.sa_sigaction = sig_handler;			//信号处理函数
	act.sa_flags = SA_SIGINFO;				//使用sa_sigaction的信号处理函数
	if(sigaction(SIGIO, &act, NULL) < 0)	//设置信号处理方式
	{
		perror("error");
		return ;
	}

	/* 2、打开设备文件 */
	noblock_fd = open(file, O_RDWR|O_NONBLOCK);
	if(noblock_fd < 0)
	{
		perror("error");
		return ;
	}

	/* 3、设置在此文件描述符上接收信号的进程标识 */
	if(fcntl(noblock_fd, F_SETOWN, getpid()) < 0)
	{
		perror("error");
		close(noblock_fd);
		return ;
	}

	/* 4、设置标识输入输出可进行的信号 */
	if(fcntl(noblock_fd, F_SETSIG, SIGIO) < 0)
	{
		perror("error");
		close(noblock_fd);
		return ;
	}

	/* 5、设置文件的FASYNC标志 */
	flag = fcntl(noblock_fd, F_GETFL);
	if(flag < 0)
	{
		perror("error");
		close(noblock_fd);
		return ;
	}
	if(fcntl(noblock_fd, F_SETFL, flag|FASYNC) < 0)
	{
		perror("error");
		close(noblock_fd);
		return ;
	}

	//等待信号被触发
	while(1)
	{
		sleep(100);
	}
}

void block_test(char *file)
{
	int ret;
	long long width;

	printf("block mode\r\n");

	block_fd = open(file, O_RDWR);
	if(block_fd < 0)
	{
		printf("can't open file %s\r\n", file);
		return ;
	}

	while (1) 
	{
		ret = read(block_fd, &width, sizeof(width));
		if(ret == sizeof(width))
			printf("width: %lld\r\n", width);
		else
			printf("read failed\r\n");
	}
}

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	if(argc < 2)
	{
		printf("Error Usage!\r\n");
		return -1;
	}

	if((argc >= 3) && !strncmp(argv[2], "NOBLOCK", 7))
		noblock_test(argv[1]);
	else
		block_test(argv[1]);

	return 0;
}

